package com.wrupple.muba.catalogs.client.module.services.logic.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONNull;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.wrupple.muba.common.domain.FilterCriteria;
import com.wrupple.muba.common.domain.FilterData;
import com.wrupple.muba.common.domain.FilterDataOrdering;
import com.wrupple.vegetate.client.module.services.logic.FilterDataSerializationService;

public class ClientSideFilterDataSerializationService implements
		FilterDataSerializationService {

	@Override
	public FilterData deserialize(String filterData) {
		// simplifiedFilterData
		
		FilterData regreso = new FilterData();
		regreso.setConstrained(true);
		regreso.setStart(0);
		regreso.setEnd(100);
		
		return regreso;
	}

	@Override
	public String serialize(FilterData filterData) {
		if(filterData==null){
			return null;
		}
		return serializeFilterData(filterData).toString();
	}
	
	private JSONValue serializeFilterData(FilterData filter) {
		if (filter == null) {
			return JSONNull.getInstance();
		}
		JSONObject regreso = new JSONObject();
		regreso.put("filters", serialize(filter.getFilters()));
		regreso.put("order", serialize(filter.getOrder()));
		regreso.put("joins", serialize(filter.getJoins()));
		regreso.put("start", new JSONNumber(filter.getStart()));
		regreso.put("end", new JSONNumber(filter.getEnd()));
		regreso.put("constrained",
				JSONBoolean.getInstance(filter.isConstrained()));
		return regreso;
	}

	private JSONValue serialize(String[][] joins) {
		if (joins == null) {
			return JSONNull.getInstance();
		}
		JSONArray array = new JSONArray();
		JSONArray temp = null;
		String[] o;
		int internalCounter ;
		for (int index = 0; index < joins.length; index++) {
			o = joins[index];
			if (o != null) {
				String s;
				temp = new JSONArray();
				internalCounter = 0;
				for(int i = 0 ; i < o.length; i++){
					s = o[i];
					if(s!=null){
						temp.set(internalCounter, new JSONString(s));
						internalCounter++;
					}
				}
				array.set(index, temp);
			}
		}
		return array;
	}

	private JSONValue serialize(ArrayList<FilterDataOrdering> order) {
		if (order == null) {
			return JSONNull.getInstance();
		}
		JSONArray array = new JSONArray();
		JSONObject temp = null;
		int index = 0;
		for (FilterDataOrdering o : order) {
			if (o.getField() != null) {
				temp = new JSONObject();
				temp.put("field", new JSONString(o.getField()));
				temp.put("ascending", JSONBoolean.getInstance(o.isAscending()));
				array.set(index, temp);
				index++;
			}
		}
		return array;
	}

	private JSONValue serialize(Map<String, List<FilterCriteria>> filters) {
		if (filters == null) {
			return JSONNull.getInstance();
		}
		JSONObject regreso = new JSONObject();
		for (String key : filters.keySet()) {
			regreso.put(key, serialize(filters.get(key)));
		}
		return regreso;
	}

	private JSONValue serialize(List<FilterCriteria> list) {
		List<FilterCriteria> parameter = list;
		if (parameter == null || parameter.isEmpty()) {
			return JSONNull.getInstance();
		}
		if (allWithSameOperator(parameter)) {
			FilterCriteria only = new FilterCriteria();
			List<String> values = new ArrayList<String>();
			for (FilterCriteria c : parameter) {

				values.addAll(c.getValues());
			}
			only.setOperator(parameter.get(0).getOperator());
			only.setValues(values);
			parameter = Arrays.asList(only);

		}

		if (parameter == null) {
			return JSONNull.getInstance();
		}
		JSONArray regreso = new JSONArray();
		JSONObject temp;
		JSONArray values;
		int count = 0;
		for (FilterCriteria c : parameter) {
			if(c==null||c.getValues()==null){
				
			}else{
				temp = new JSONObject();
				String value;
				values = new JSONArray();
				for (int i = 0; i < c.getValues().size(); i++) {
					value = c.getValues().get(i);
					if (value != null) {
						values.set(i, new JSONString(value));
					}
				}
				temp.put("values", values);
				temp.put("operator", new JSONString(c.getOperator()));
				regreso.set(count, temp);
				count++;
			}
			
		}
		return regreso;
	}

	private boolean allWithSameOperator(List<FilterCriteria> list) {
		if (list == null || list.isEmpty() || list.size() == 1) {
			return false;
		} else {
			boolean regreso = true;
			String op = list.get(0).getOperator();
			for (FilterCriteria c : list) {
				if (op.equals(c.getOperator())) {

				} else {
					regreso = false;
				}
			}
			return regreso;
		}

	}

}
